﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace Antioch.Base
{
    public class BulletModule : Jemgine.Engine.Module
    {
        public enum BulletTarget
        {
            Player,
            Enemy
        }

        class Bullet
        {
            internal Vector2 Position;
            internal Vector2 Orientation;
            internal float Velocity;
            internal float Lifetime;
            internal BulletTarget Target;
            internal Weapon FiredBy;
        }

        List<Bullet> ActiveBullets = new List<Bullet>();
        List<Bullet> RecycledBullets = new List<Bullet>();
        Jemgine.Engine.PhysicsModule PhysicsModule;
        Jemgine.Engine.Particles.ParticleModule ParticleModule;

        Texture2D texBullet;

        public BulletModule(ContentManager Content)
        {
            texBullet = Content.Load<Texture2D>("Antioch.Content/frame");
        }

        public override void BeginSimulation()
        {
            foreach (var Bullet in ActiveBullets)
                RecycledBullets.Add(Bullet);
            ActiveBullets.Clear();

            PhysicsModule = Sim.GetModule<Jemgine.Engine.PhysicsModule>();
            ParticleModule = Sim.GetModule<Jemgine.Engine.Particles.ParticleModule>();

            base.BeginSimulation();
        }

        public void FireBullet(Vector2 Position, Vector2 Direction, float Velocity, BulletTarget Target,
            Weapon FiredBy)
        {
            Direction.Normalize();

            Bullet _bullet = null;
            if (RecycledBullets.Count > 0)
            {
                _bullet = RecycledBullets[RecycledBullets.Count - 1];
                RecycledBullets.RemoveAt(RecycledBullets.Count - 1);
            }
            else
                _bullet = new Bullet();

            _bullet.Lifetime = 100.0f;
            _bullet.Position = Position;
            _bullet.Orientation = Direction;
            _bullet.Velocity = Velocity;
            _bullet.Target = Target;
            _bullet.FiredBy = FiredBy;

            ActiveBullets.Add(_bullet);
        }

        private bool BulletCollisionFilter(Jemgine.Engine.Physics Physics, Bullet _bullet)
        {
            if (Physics.CollisionGroup == Jemgine.Engine.Physics.CollisionGroups.World)
            {
                Jemgine.Engine.PolygonPhysics PolygonPhysics = Physics as Jemgine.Engine.PolygonPhysics;
                if (PolygonPhysics != null && PolygonPhysics.PhysicsType != Jemgine.Engine.PolygonPhysicsType.Normal) return false;
                return true;
            }
            switch (_bullet.Target)
            {
                case BulletTarget.Enemy:
                    if (Physics.CollisionGroup == Jemgine.Engine.Physics.CollisionGroups.Enemy) return true;
                    break;
                case BulletTarget.Player:
                    if (Physics.CollisionGroup == Jemgine.Engine.Physics.CollisionGroups.Player) return true;
                    break;
            }
            return false;
        }                

        public override void Update(float ElapsedSeconds)
        {
            for (int B = 0; B < ActiveBullets.Count; )
            {
                bool Destroy = false;

                Vector2 Delta = ActiveBullets[B].Orientation * ActiveBullets[B].Velocity * ElapsedSeconds;
                var RaycastResult = PhysicsModule.RayCast(ActiveBullets[B].Position, ActiveBullets[B].Position + Delta,
                    (A) => BulletCollisionFilter(A, ActiveBullets[B]));
                if (RaycastResult.Hit == false)
                    ActiveBullets[B].Position += Delta;
                else
                {
                    if (RaycastResult.PhysicsComponent != null && RaycastResult.PhysicsComponent.Me != null)
                    {
                        var Health = RaycastResult.PhysicsComponent.Me.GetComponent<Health>();
                        if (Health != null) Health.TakeDamage(1);

                        if (ActiveBullets[B].FiredBy != null)
                            ParticleModule.FireEffect(RaycastResult.Point,
                            Jemgine.Math.Vector.AngleBetweenVectors(Vector2.UnitY, RaycastResult.Normal),
                            ActiveBullets[B].FiredBy.HitWorldEffect);
                    }
                    ActiveBullets[B].Position = RaycastResult.Point;
                    Destroy = true;
                }

                ActiveBullets[B].Lifetime -= ElapsedSeconds;
                if (ActiveBullets[B].Lifetime <= 0.0f) Destroy = true;

                if (Destroy)
                {
                    RecycledBullets.Add(ActiveBullets[B]);
                    ActiveBullets.RemoveAt(B);
                }
                else
                    ++B;
            }

            base.Update(ElapsedSeconds);
        }

        public void Draw(Jemgine.Renderer.RenderContext RenderContext)
        {
            for (int B = 0; B < ActiveBullets.Count; ++B)
                RenderContext.DrawOrientedSprite(texBullet, ActiveBullets[B].Position, ActiveBullets[B].Orientation / 2);
        }

    }
}
